package com.chuanke.ckfamily.service.common.impl;

import com.chuanke.ckfamily.service.common.CacheService;
import com.chuanke.ckfamily.service.common.RSAService;
import com.chuanke.ckfamily.service.common.model.RSAKey;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import java.security.*;

/**
 * Created by wangbin on 2017/7/2.
 */
@Service
public class RSAServiceImpl implements RSAService {

    private static final Logger log = LoggerFactory.getLogger(RSAServiceImpl.class);

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 1024;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    private static final String RSA_KEY = "LOGIN_RSAKEY_KEY";
    
    private static final String RSA_KEY_MSG = "MSG_RSAKEY";//会话

	private static final long rsa_key_msg_time = 1000*60*60*24;

    @Autowired
    private CacheService<String, Object> cacheService;

    @Override
    public String getPublicKey() {
        try {
            PublicKey publicKey = getRSAKey().getKeyPair().getPublic();
            BASE64Encoder base64Encoder=new BASE64Encoder();
            return base64Encoder.encodeBuffer(publicKey.getEncoded());

        } catch (Exception e) {
            e.printStackTrace();
            return null;

        }
    }

    @Override
    public String encrypt(String data) {
        PublicKey publicKey = getRSAKey().getKeyPair().getPublic();
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] output = cipher.doFinal(data.getBytes("UTF-8"));
            return new BASE64Encoder().encodeBuffer(output);

        } catch (Exception e) {
            e.printStackTrace();
            return null;

        }
    }
    
    @Override
    public String encryptByPrivateKey(String data,PrivateKey privateKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] output = cipher.doFinal(data.getBytes("UTF-8"));
            return new BASE64Encoder().encodeBuffer(output);

        } catch (Exception e) {
            e.printStackTrace();
            return null;

        }
    }
    @Override
    public String decryptByPublicKey(String cipherData,PublicKey publicKey) {
        try {
            Cipher cipher= Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] output = cipher.doFinal(new BASE64Decoder().decodeBuffer(cipherData));
            return new String(output, "UTF-8").trim();

        } catch (Exception e) {
            e.printStackTrace();
            return null;

        }
    }

    @Override
    public String decrypt(String cipherData) {
        if (StringUtils.isEmpty(cipherData)) {
            return null;
        }

        try {
            log.debug("cipherData : " + cipherData);
            PrivateKey privateKey = getRSAKey().getKeyPair().getPrivate();
            Cipher cipher= Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] output = cipher.doFinal(new BASE64Decoder().decodeBuffer(cipherData));
            return new String(output, "UTF-8").trim();

        } catch (Exception e) {
            e.printStackTrace();
            return null;

        }
    }

    public RSAKey getRSAKey() {
        RSAKey rsaKey = (RSAKey)cacheService.get(RSA_KEY);
        if (rsaKey == null || rsaKey.getInvlidateTime() < System.currentTimeMillis() - 3600000) {
            rsaKey = createKey();
            cacheService.set(RSA_KEY, rsaKey);
        }

//        BASE64Encoder base64Encoder=new BASE64Encoder();
//        String publicKeyString = base64Encoder.encode(rsaKey.getKeyPair().getPublic().getEncoded());
//        String privateKeyString = base64Encoder.encode(rsaKey.getKeyPair().getPrivate().getEncoded());
//
//        log.debug("publicKey={}; privateKey={}", rsaKey.getKeyPair().getPublic(), rsaKey.getKeyPair().getPrivate());
        
        return rsaKey;
    }

    private RSAKey createKey() {
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        keyPairGen.initialize(1024,new SecureRandom());
        KeyPair keyPair = keyPairGen.generateKeyPair();
        return new RSAKey(keyPair);
    }

    @Override
	public RSAKey getRSAKeyMsg() {
		RSAKey rsaKey = (RSAKey)cacheService.get(RSA_KEY_MSG);
		long currentTimeMillis = System.currentTimeMillis();
        if (rsaKey == null || rsaKey.getInvlidateTime() < currentTimeMillis) {
            rsaKey = createKey();
            long invlidateTime=currentTimeMillis+rsa_key_msg_time;
            rsaKey.setInvlidateTime(invlidateTime);
            cacheService.set(RSA_KEY_MSG, rsaKey);
        }
		return rsaKey;
	}
}
